package com.qiyu.tech.pay.queue.handler;

import com.qiyu.tech.pay.dao.WXPayConfigDao;
import com.qiyu.tech.pay.entity.WXPayConfigPO;
import com.qiyu.tech.pay.queue.*;
import com.qiyu.tech.pay.queue.model.DelayTaskInfo;
import com.qiyu.tech.pay.queue.model.DelayTaskSortItem;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;

import java.util.UUID;

import static com.qiyu.tech.pay.constants.PayConfigConstants.*;

/**
 * 专门用于处理就绪队列内部的任务信息
 *
 * @Author idea
 * @Date created in 11:35 上午 2021/4/3
 */
@Component
@Slf4j
public class RedisReadyQueueHandler implements Runnable {

    @Resource
    private RedisReadyQueue redisReadyQueue;
    @Resource
    private RedisDelayQueue redisDelayQueue;
    @Resource
    private DelayTaskInfoManager delayTaskInfoManager;
    @Resource
    private WXPayConfigDao wxPayConfigDao;
    @Resource
    private NotifyErrorTaskInfoManager notifyErrorTaskInfoManager;
    @Resource
    private NotifyRetryTaskInfoManager notifyRetryTaskInfoManager;


    @SneakyThrows
    @Override
    public void run() {
        while (true) {
            Thread.sleep(1000);
            DelayTaskInfo delayTaskInfo = redisReadyQueue.pop();
            if (delayTaskInfo == null) {
                continue;
            }
            log.info("弹出任务：delayTaskInfo is {}",delayTaskInfo);
            ResponseEntity<String> responseEntity = null;
            try {
                WXPayConfigPO wxPayConfigPO = wxPayConfigDao.getByPayConfigId(delayTaskInfo.getPayConfigId());
                responseEntity = this.doBusinessNotify(delayTaskInfo,wxPayConfigPO);
                if (HttpStatus.OK.equals(responseEntity.getStatusCode()) && "success".equals(responseEntity.getBody())) {
                    log.info("支付回调成功！====== ");
                    //删除失败任务map中的记录
                    notifyErrorTaskInfoManager.delete(delayTaskInfo.getTaskId());
                    notifyRetryTaskInfoManager.delete(delayTaskInfo.getTaskId());
                } else {
                    throw new RuntimeException("支付业务回调失败");
                }
            }catch (Exception e){
                log.error("支付业务回调失败===== responseEntity is {}", responseEntity);
                retryAgain(delayTaskInfo);
            }
        }
    }

    /**
     * 业务内部系统回调处理
     *
     * @param delayTaskInfo
     * @param wxPayConfigPO
     * @return
     */
    public ResponseEntity<String> doBusinessNotify(DelayTaskInfo delayTaskInfo,WXPayConfigPO wxPayConfigPO){
        RestTemplate restTemplate = new RestTemplate();
        HttpHeaders headers = new HttpHeaders();
        headers.add("pay-token", createPayNotifySeq());
        //业务回调参数
        String message = delayTaskInfo.getMessage();
        MultiValueMap<String, String> paramMap = new LinkedMultiValueMap<>();
        paramMap.add("extInfo", message);
        HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(paramMap, headers);
        log.info("wxPayConfigPO is {},paramMap is {},headers is {}", wxPayConfigPO, paramMap, headers);
        ResponseEntity<String> responseEntity  = restTemplate.postForEntity(wxPayConfigPO.getBussinessNotifyUrl(), request, String.class);
        return responseEntity;
    }

    /**
     * 创建业务方回调使用的seq序列号
     *
     * @return
     */
    public String createPayNotifySeq(){
        return UUID.randomUUID().toString();
    }

    /**
     * 进入重试阶段
     *
     * @param delayTaskInfo
     */
    public void retryAgain(DelayTaskInfo delayTaskInfo){
        log.info("支付重试：delayTaskInfo is :{}",delayTaskInfo);
        //进入支付重试环节
        int retryTime = delayTaskInfo.getRetryTimes();

        if(retryTime >= RETRY_TIMES.length) {
            notifyRetryTaskInfoManager.delete(delayTaskInfo.getTaskId());
            //超过重试还是异常的信息存在这张map中
            notifyErrorTaskInfoManager.put(delayTaskInfo.getTaskId(),delayTaskInfo);
            return;
        }
        delayTaskInfo.setExecuteTime(System.currentTimeMillis() + RETRY_TIMES[retryTime] * 1000 );
        delayTaskInfo.setExecuteTimeout(delayTaskInfo.getExecuteTimeout() + DEFAULT_TIME_OUT);
        delayTaskInfo.setRetryTimes(retryTime+1);
        DelayTaskSortItem delayTaskSortItem = new DelayTaskSortItem(delayTaskInfo.getTaskId(),PAY_TOPIC,delayTaskInfo.getExecuteTime());
        delayTaskInfoManager.put(delayTaskInfo.getTaskId(),delayTaskInfo);
        redisDelayQueue.put(delayTaskSortItem);
        //将重试的信息放入到一张map里面做管理
        notifyRetryTaskInfoManager.put(delayTaskInfo.getTaskId(),delayTaskInfo);
    }
}
